iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
自我挑戰組

入坑 RoR 必讀 - Ruby 物件導向設計實踐系列 第 15

Day15 CH7使用模組共用角色行爲(下)

  • 分享至 

  • xImage
  •  

昨天,我們認識了角色,鴨子類別是一種 角色 ,能夠表現共同行為的角色都算是鴨子類別。再來,我們可以定義一組獨立於類別的方法,並且可以被其他物件使用,稱為 模組 (module)

今天,我們要接著來看模組內的方法是如何自動委派給其他物件使用,他與經典繼承又有什麼不同。

尋找方法的模式

經典繼承

當物件接收到訊息時,OO語言首先會在該物件的類別裡尋找符合的方法實作,如果類別沒有實作該訊息,則繼續搜尋它的父類別。這個搜尋會沿著父類別鏈繼續向上,並在一層層的父類別裡尋找,直到層次結構的頂端。

https://ithelp.ithome.com.tw/upload/images/20230916/20145409e9w9zEBHIV.jpg

外掛模組

注意在BicycleObject之間突顯了一個Schedulable模組。

https://ithelp.ithome.com.tw/upload/images/20230916/20145409Se4OIsUZNR.jpg

  • Bicycle類別外掛了Schedulable這個模組時,其定義的所有方法都會成為Bicycle的可回應方法
  • Bicycle的父類別不會因為包含這個模組而有所變化(仍然是object)
  • 如果Bicycle實作了某個方法,它在Schedulable裡也有被定義, 那麼Bicycle的實作將會覆蓋Schedulable裡的相同方法。
  • 特性:
    • 模組可以包含方法,並且將這些方法添加到物件的可回應方法中。
    • 單一類別包含多個不同模組時,最後被包括的模組方法在尋找路徑裡會處於第一位(由下往上搜尋)。
    • 使用includeextend
      • 使用Ruby的 include 關鍵字將模組包括到類別中,將模組方法添加到該類別的所有實例的可回
        應方法中。
      • 使用Ruby的 extend 關鍵字將模組添加到特定物件中,將模組方法添加到該物件的可回方法中。
      • 類別方法實例方法 的建立方式相同,只是類別方法位於類別中,而實例方法位於實例中。

https://ithelp.ithome.com.tw/upload/images/20230916/20145409lYx0Bl0gXf.jpg

單例類別(Singleton class)

任何物件都可以擁有自己的單例類別,並在其中直接添加特定方法,這些方法專屬於該物件。

方法定義的位置影響方法的可回應集,使用不同的方法來擴展物件的可回應集,可以將方法定義放置在不同的位置,如類別模組實例,或單例類別

撰寫可繼承的程式碼

識別出反面模式

  1. 物件使用typecategory這類名稱的變數來確認傳送給self的是何種訊息,該訊息包含兩種極為相關卻又有所不同的類型。像這樣的程式碼可以使用經典繼承,將共同的程式碼放置在某個抽象父類別裡,並為各個不同的類型建立子類別。

  2. 傳送物件要檢查接收物件的類別以確認所應傳送的訊息,那麼便忽略了鴨子類型的存在。在這種情況下,所有可能的接收物件都在扮演某個共同角色。這個角色應該被程式碼撰寫為一種鴨子類型,而接收者則應該實作這個鴨子類型的介面

堅持抽象

抽象父類別裡的所有程式碼都應該適用於每一個繼承它的類別。父類別不應該包含只適用於部分(而非全部)子類別的程式碼。

重視契約

子類別都同意這樣的契約:它們都承諾能夠代替其父類別。只有當物件如預期般表現,並且子類別也合乎預期的遵從其父類別介面,才可能具有可代替性。它們都必須回應該介面裡的每一則訊息,接收相同類型的輸入,以及傳回相同類型的輸出。其他物件應當不需要對其進行類型檢查,就能夠知道該如何對待或是期望它們。

使用範本方法

用於建立可繼承程式碼的基本撰寫技巧是使用範本方法模式,這種模式可以讓你將抽象與具體分離開來。

預先解耦類別

請避免撰寫需要繼承者傳送super的程式碼。可以藉由鉤子訊息讓子類別參與進來,同時還可免除它們需要知道抽象演算法的職責。

建立淺層結構

每一個層次結構都可以想成是一座金字塔,它有深度和廣度。物件的深度是指在它和頂端之間所有父類別的數量,而廣度則指的是它的直接子類別數量。

深窄的層次結構有著更高的難度,並且很不幸地,它們的寬度其實會逐漸增加,這是出於其深度所造成的副作用。深寬的層次結構難以理解與維護,應該要加以避免。

https://ithelp.ithome.com.tw/upload/images/20230916/201454097HJqAsoHVD.jpg

結論

  • 當扮演共同角色的物件需要共用行為時,它們可以藉由Ruby模組來達成。
  • 模組裡定義的程式碼可以增加到任何物件,其中包括類別實例、類別本身或者是另一個模組。
  • 當類別包含模組時,模組方法會進入到與繼承方法相同的尋找路徑。由於模組方法和繼承方法都是插入於尋找路徑裡,所以模組撰寫技巧就是繼承撰寫技巧的翻版。
  • 模組應該使用範本方法模式,讓包含它們的類別可以提供特殊化內容。
  • 模組應該實作鉤子方法,避免迫使那些類別傳送super(導致它們知悉演算法)。

參考資料:

  • *Practical Object-Oriented Design in Ruby: An Agile Primer *

上一篇
Day14 CH7使用模組共用角色行爲(上)
下一篇
Day16 CH8組合物件(上)
系列文
入坑 RoR 必讀 - Ruby 物件導向設計實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言